#include "OiPCH.hpp"
#include <QComboBox>
#include <QtCharts/QChartView>
#include <QtSql/QSqlTableModel>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
#include <xlsxdocument.h>
#include <omp.h>

namespace Oi
{
    namespace PLScannerDll
    {
        using namespace QtCharts;
        using namespace PLScannerCore;

        class MonthSelectWidgetImpl : public Impl<MonthSelectWidget>
        {
        public:
            QComboBox* _year;
            QComboBox* _month;
        };

        MonthSelectWidget::MonthSelectWidget(QWidget* parent/* = nullptr*/)
            : QWidget(parent)
        {
            OI_I(MonthSelectWidget);
            QHBoxLayout* layout = new QHBoxLayout(this);
            QLabel* label = new QLabel(RecordPage::tr("年/月: "));
            d->_year = new QComboBox();
            d->_month = new QComboBox();

            layout->addWidget(label);
            layout->addWidget(d->_year);
            layout->addWidget(d->_month);
            layout->addStretch(1);

            auto now = QDate::currentDate();

            for (int i = now.year(); i >= 2018; i--)
            {
                d->_year->addItem(QString::number(i), i);
            }

            for(int i = 1; i <= 12; i++)
            {
                d->_month->addItem(QString::number(i), i);
            }

            connect(d->_year, SIGNAL(currentIndexChanged(int)), this, SLOT(onSelectedChanged()));
            connect(d->_month, SIGNAL(currentIndexChanged(int)), this, SLOT(onSelectedChanged()));
        }

        QDate MonthSelectWidget::month() const
        {
            OI_C(MonthSelectWidget);
            return QDate(d->_year->currentData().toInt(), d->_month->currentData().toInt(), 1);
        }

        void MonthSelectWidget::setMouth(const QDate dd)
        {
            OI_F(MonthSelectWidget);

            d->_year->blockSignals(true);
            d->_month->blockSignals(true);

            auto yi = d->_year->findData(dd.year());
            if (yi >= 0)
            {
                d->_year->setCurrentIndex(yi);
            }

            auto mi = d->_month->findData(dd.month());
            if(mi >= 0)
            {
                d->_month->setCurrentIndex(mi);
            }

            d->_year->blockSignals(false);
            d->_month->blockSignals(false);

            onSelectedChanged();
        }

        void MonthSelectWidget::onSelectedChanged()
        {
            OI_F(MonthSelectWidget);
            emit monthChanged(QDate(d->_year->currentData().toInt(), d->_month->currentData().toInt(), 1));
        }

        class statisticsTimeDlgImpl : public Impl<statisticsTimeDlg>
        {
    
        public:
            MonthSelectWidget* _month;
            QChartView *_chartView;
            ValueInDateChart* _chart;
            QTableWidget* _table;
        };

        statisticsTimeDlg::statisticsTimeDlg(QWidget* parent /*= nullptr*/)
            : QDialog(parent, Qt::Dialog)
        {
            OI_I(statisticsTimeDlg);
            QVBoxLayout* mainLayout = new QVBoxLayout(this);

            d->_month = new MonthSelectWidget();

            d->_chart = new ValueInDateChart();

            d->_chartView = new ValueInDateChartView(d->_chart);

            d->_table = new QTableWidget();
            d->_table->setRowCount(3);
            d->_table->setFixedHeight(150);
            QStringList sideList;
            sideList << statisticsTimeDlg::tr("稼动时间") << statisticsTimeDlg::tr("空闲时间") << statisticsTimeDlg::tr("稼动率(%)") ;
            d->_table->setVerticalHeaderLabels(sideList);
            d->_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

            mainLayout->addWidget(d->_month, 0);
            mainLayout->addWidget(d->_chartView, 1);
            mainLayout->addWidget(d->_table, 0);

            connect(d->_month, &MonthSelectWidget::monthChanged, this, &statisticsTimeDlg::updateMonth);

            d->_month->setMouth(QDate::currentDate());
        }

        void statisticsTimeDlg::updateMonth(QDate dt)
        {
            OI_F(statisticsTimeDlg);

            QDateTime from(dt);
            QDateTime end(dt.addMonths(1));

            int dn = from.daysTo(end);

            auto thread_num = 2 * omp_get_num_procs() - 1;
            omp_set_num_threads(thread_num);

            QList<int> busyMins, idleMins;
            QList<double> busyRatio;

            for(int i = 0; i < dn; i++)
            {
                busyMins << 0;
                idleMins << 0;
                busyRatio << 0.0;
            }

        #pragma omp parallel 
            {
            #pragma omp for 
                for(int i = 0; i < dn; i++)
                {
                    int busyM = 0;
                    int idleM = 0;

                    QSqlQuery query;

                    QDateTime dayFrom = from.addDays(i);
                    QDateTime dayEnd = from.addDays(i + 1);

                    qreal sdt, edt, ldt;
                    sdt = edt = dayFrom.toMSecsSinceEpoch();
                    ldt = dayEnd.toMSecsSinceEpoch();

                    query.prepare(QString("SELECT %1 FROM %2 WHERE datetime BETWEEN '%3' AND '%4'")
                        .arg("datetime")
                        .arg(Database::instance()->tableName())
                        .arg(dayFrom.toString("yyyy-MM-dd hh:mm:ss"))
                        .arg(dayEnd.toString("yyyy-MM-dd hh:mm:ss")));

                    query.exec();

                    while(query.next())
                    {
                        qreal datetime = query.value(0).toDateTime().toMSecsSinceEpoch();

                        if(datetime - edt > 5 * 60 * 1000)
                        {
                            if(edt != sdt)
                            {
                                busyM += qRound(( edt - sdt ) / 60000);
                            }

                            idleM += qRound(( datetime - edt ) / 60000);

                            sdt = edt = datetime;
                        }
                        else
                        {
                            edt = datetime;
                        }
                    }

                    if(ldt - edt > 5 * 60 * 1000)
                    {
                        if(edt != sdt)
                        {
                            busyM += qRound(( edt - sdt ) / 60000);
                        }

                        idleM += qRound(( ldt - edt ) / 60000);
                    }
                    else
                    {
                        edt = ldt;

                        if(edt != sdt)
                        {
                            busyM += qRound(( edt - sdt ) / 60000);
                        }
                    }

                    busyMins[i] = busyM;
                    idleMins[i] = idleM;
                    busyRatio[i] = 100.0 * busyM / ( busyM + idleM );
                }
            }

            d->_chart->setValues(2, busyRatio, dn);

            d->_table->clearContents();
            d->_table->setColumnCount(dn);

            for (int i = 0; i < d->_table->columnCount(); i++)
            {
                QTableWidgetItem* item = d->_table->item(0, i);
                if (item)
                {
                    item->setText(QString::number(busyMins[i]));
                }
                else
                {
                    d->_table->setItem(0, i, new QTableWidgetItem(QString::number(busyMins[i])));
                }

                item = d->_table->item(1, i);
                if(item)
                {
                    item->setText(QString::number(idleMins[i]));
                }
                else
                {
                    d->_table->setItem(1, i, new QTableWidgetItem(QString::number(idleMins[i])));
                }

                item = d->_table->item(2, i);

                if(item)
                {
                    item->setText(QString::number(idleMins[i]));
                }
                else
                {
                    d->_table->setItem(2, i, new QTableWidgetItem(QString::number(busyRatio[i], 'f', 2)));
                }
            }
        }

        class statisticsRatioDlgImpl : public Impl<statisticsRatioDlg>
        {
        public:
            struct ratioData
            {
                double tcp = 0.0;
                double tcpk = 0.0;
                double tokRatio = 0.0;
                double wcp = 0.0;
                double wcpk = 0.0;
                double wokRatio = 0.0;
                int count = 0;
            };
        public:
            MonthSelectWidget* _month;
            QComboBox* _order;
            QTableWidget* _table;
            QPushButton *_export;

        public:
            void updateTol(const QString formular, double& upper, double& lower, int index, QString key);
        };

        statisticsRatioDlg::statisticsRatioDlg(QWidget* parent /*= nullptr*/)
            : QDialog(parent, Qt::Dialog)
        {
            OI_I(statisticsRatioDlg);
            QVBoxLayout* mainLayout = new QVBoxLayout(this);

            QHBoxLayout* tLayput = new QHBoxLayout();

            d->_month = new MonthSelectWidget();
            QLabel* orderLable = new QLabel("班次");
            d->_order = new QComboBox();
            d->_export = new QPushButton("导出");

            d->_order->addItems({statisticsRatioDlg::tr("全部"), statisticsRatioDlg::tr("A班"), statisticsRatioDlg::tr("B班"), statisticsRatioDlg::tr("C班") });

            d->_order->setCurrentIndex(0);

            d->_table = new QTableWidget();
            d->_table->verticalHeader()->hide();

            tLayput->addWidget(d->_month);
            tLayput->addStretch(1);
            tLayput->addWidget(orderLable);
            tLayput->addWidget(d->_order);
            tLayput->addStretch(8);
            tLayput->addWidget(d->_export);

            mainLayout->addLayout(tLayput);
            mainLayout->addWidget(d->_table);

            connect(d->_month, &MonthSelectWidget::monthChanged, this, &statisticsRatioDlg::updateTime);
            connect(d->_order, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &statisticsRatioDlg::updateTime);
            connect(d->_export, &QPushButton::clicked, this, &statisticsRatioDlg::onExport);

            d->_month->setMouth(QDate::currentDate());
        }

        void statisticsRatioDlgImpl::updateTol(const QString formular, double& stdValue, double& errorTol, int index, QString key)
        {
            errorTol = 0.0;
            stdValue = 0.0;

            ProductParams params;
            if (ProductParams::loadFromLocal(params, formular))
            {
                params.getMeasureErrorTol(index, key, errorTol);
                params.getStdValue(index, key, stdValue);
            }
        }

        void statisticsRatioDlg::updateTime()
        {
            OI_F(statisticsRatioDlg);

#if 1
            QDate dt = d->_month->month();
            int team = d->_order->currentIndex() - 1;

            QDateTime from(dt);
            QDateTime end(dt.addMonths(1));
            int dn = from.daysTo(end);
            
            auto thread_num = 2 * omp_get_num_procs() - 1;
            omp_set_num_threads(thread_num);

            QList<QMap<QString, statisticsRatioDlgImpl::ratioData>> datas;
            QStringList formulars;

            QList <QMap<QString, QList<double>>> thicknessValues;
            QList <QMap<QString, QList<double>>> widthValues;

            QMap<QString, QList<double>> stdValues;
            QMap<QString, QList<double>> tolValues;

            QSqlQuery query;

            if (team < 0)
            {
                query.prepare(QString("SELECT %1 FROM %2 WHERE datetime BETWEEN '%3' AND '%4' GROUP BY %1 ")
                    .arg("formula")
                    .arg(Database::instance()->tableName())
                    .arg(from.toString("yyyy-MM-dd hh:mm:ss"))
                    .arg(end.toString("yyyy-MM-dd hh:mm:ss")));

                query.exec();
            }
            else
            {  
                query.prepare(QString("SELECT %1 FROM %2 WHERE team = %5 AND datetime BETWEEN '%3' AND '%4' GROUP BY %1 ")
                    .arg("formula")
                    .arg(Database::instance()->tableName())
                    .arg(from.toString("yyyy-MM-dd hh:mm:ss"))
                    .arg(end.toString("yyyy-MM-dd hh:mm:ss"))
                    .arg(team));

                query.exec();
            }

            while(query.next())
            {
                auto value0 = query.value(0).toString();
                if(!value0.isEmpty())
                {
                    formulars.push_back(value0);
                }
            }
            
            for(int i = 0; i < dn; i++)
            {
                QMap<QString, statisticsRatioDlgImpl::ratioData> singleday;

                for (auto f : formulars)
                {
                    singleday[f] = statisticsRatioDlgImpl::ratioData();
                }

                datas << singleday;

                thicknessValues << QMap<QString, QList<double>>();
                widthValues << QMap<QString, QList<double>>();
            }

            for (auto f : formulars)
            {
                double thickness1Std = 0.0, thickness2Std = 0.0, thickness3Std = 0.0, thickness4Std = 0.0, thickness5Std = 0.0, widthStd = 0.0;
                double thickness1Tol = 0.0, thickness2Tol = 0.0, thickness3Tol = 0.0, thickness4Tol = 0.0, thickness5Tol = 0.0, widthTol = 0.0;

                d->updateTol(f, thickness1Std, thickness1Tol, TT_MeasureThicknessTool + 0, "y");
                d->updateTol(f, thickness2Std, thickness2Tol, TT_MeasureThicknessTool + 1, "y");
                d->updateTol(f, thickness3Std, thickness3Tol, TT_MeasureThicknessTool + 2, "y");
                d->updateTol(f, thickness4Std, thickness4Tol, TT_MeasureThicknessTool + 3, "y");
                d->updateTol(f, widthStd, widthTol, TT_TotolWidth, "x");
                stdValues[f].append(thickness1Std);
                stdValues[f].append(thickness2Std);
                stdValues[f].append(thickness3Std);
                stdValues[f].append(thickness4Std);
                stdValues[f].append(widthStd);

                tolValues[f].append(thickness1Tol);
                tolValues[f].append(thickness2Tol);
                tolValues[f].append(thickness3Tol);
                tolValues[f].append(thickness4Tol);
                tolValues[f].append(widthTol);
            }

        #pragma omp parallel 
            {
            #pragma omp for 
                for(int i = 0; i < dn; i++)
                {
                    auto & tvalues = thicknessValues[i];
                    auto & wvalues = widthValues[i];

                    QSqlQuery query;

                    QDateTime dayFrom = from.addDays(i);
                    QDateTime dayEnd = from.addDays(i + 1);

                    if(team < 0)
                    {
                        query.prepare(QString("SELECT formula,总宽,边厚T1,中厚T2,中厚T3,边厚T4 "
                            "FROM %1 WHERE datetime BETWEEN '%2' AND '%3'")
                            .arg(Database::instance()->tableName())
                            .arg(dayFrom.toString("yyyy-MM-dd hh:mm:ss"))
                            .arg(dayEnd.toString("yyyy-MM-dd hh:mm:ss")));
                    }
                    else
                    {
                        query.prepare(QString("SELECT formula,总宽,边厚T1,中厚T2,中厚T3,边厚T4 "
                            "FROM %1 WHERE team = %4 AND datetime BETWEEN '%2' AND '%3'")
                            .arg(Database::instance()->tableName())
                            .arg(dayFrom.toString("yyyy-MM-dd hh:mm:ss"))
                            .arg(dayEnd.toString("yyyy-MM-dd hh:mm:ss"))
                            .arg(team));
                    }
                        
                    if (!query.exec())
                    {
                        OiWarning() << query.lastError();
                    }

                    while(query.next())
                    {
                        auto f = query.value(0).toString();
                        auto w = query.value(1).toDouble();
                        auto t1 = query.value(2).toDouble();
                        auto t2 = query.value(3).toDouble();
                        auto t3 = query.value(4).toDouble();
                        auto t4 = query.value(5).toDouble();

                        if(!f.isEmpty())
                        {
                            if (stdValues[f][0] > 0.0)
                            {
                                tvalues[f].append(t1 - stdValues[f][0]);
                            }

                            if (stdValues[f][1] > 0.0)
                            {
                                tvalues[f].append(t2 - stdValues[f][1]);
                            }

                            if (stdValues[f][2] > 0.0)
                            {
                                tvalues[f].append(t3 - stdValues[f][2]);
                            }

                            if (stdValues[f][3] > 0.0)
                            {
                                tvalues[f].append(t4 - stdValues[f][3]);
                            }

                            if (stdValues[f][4] > 0.0)
                            {
 //                               tvalues[f].append(t5 - stdValues[f][4]);
                            }

                            wvalues[f].append(w - stdValues[f][4]);
                        }
                    }
                    
                    for (auto iter = wvalues.begin(); iter != wvalues.end(); iter++)
                    {
                        auto f = iter.key();
                        auto c = iter->size();

                        if (datas[i].contains(f) && c > 0)
                        {
                            double tcp = 0.0, tcpk = 0.0, tokRatio = 0.0, wcp = 0.0, wcpk = 0.0, wokRatio = 0.0;
                            PLScannerUtil::calCPCPK(tvalues[f], tcp, tcpk, +tolValues[f][0], -tolValues[f][0]);
                            PLScannerUtil::calFPY(tvalues[f], tokRatio, +tolValues[f][0], -tolValues[f][0]);

                            PLScannerUtil::calCPCPK(wvalues[f], wcp, wcpk, tolValues[f][4], -tolValues[f][4]);
                            PLScannerUtil::calFPY(wvalues[f], wokRatio, +tolValues[f][4], -tolValues[f][4]);

                            datas[i][f].count = c;
                            datas[i][f].tcp = tcp;
                            datas[i][f].tcpk = tcpk;
                            datas[i][f].tokRatio = tokRatio;
                            datas[i][f].wcp = wcp;
                            datas[i][f].wcpk = wcpk;
                            datas[i][f].wokRatio = wokRatio;
                        }
                    }
                }
            }

            d->_table->clear();
            d->_table->setColumnCount(dn + 2);
            d->_table->setRowCount(7 * formulars.size());

            QStringList hts;
            hts << RecordPage::tr("规格") << RecordPage::tr("项目");
            for (int i = 0; i < dn; i++)
            {
                hts << RecordPage::tr("%1日").arg(i+1);
            }
            d->_table->setHorizontalHeaderLabels(hts);

            d->_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
            d->_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
            d->_table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);

            for (int i = 0; i < formulars.size(); i++)
            {
                d->_table->setSpan(i*7, 0, 7, 1);
                QTableWidgetItem* item = d->_table->item(i*7, 0);

                if(item)
                {
                    item->setText(formulars[i]);
                }
                else
                {
                    d->_table->setItem(i * 7, 0, new QTableWidgetItem(formulars[i]));
                }

                item = d->_table->item(i * 7 + 0, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("厚度CP"));
                }
                else
                {
                    d->_table->setItem(i * 7 + 0, 1, new QTableWidgetItem(RecordPage::tr("厚度CP")));
                }

                item = d->_table->item(i * 7 + 1, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("厚度CPK"));
                }
                else
                {
                    d->_table->setItem(i * 7 + 1, 1, new QTableWidgetItem(RecordPage::tr("厚度CPK")));
                }

                item = d->_table->item(i * 7 + 2, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("厚度合格率"));
                }
                else
                {
                    d->_table->setItem(i * 7 + 2, 1, new QTableWidgetItem(RecordPage::tr("厚度合格率")));
                }

                item = d->_table->item(i * 7 + 3, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("总宽CP"));
                }
                else
                {
                    d->_table->setItem(i * 7 + 3, 1, new QTableWidgetItem(RecordPage::tr("总宽CP")));
                }

                item = d->_table->item(i * 7 + 4, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("总宽CPK"));
                }
                else
                {
                    d->_table->setItem(i * 7 + 4, 1, new QTableWidgetItem(RecordPage::tr("总宽CPK")));
                }

                item = d->_table->item(i * 7 + 5, 1);
                if (item)
                {
                    item->setText(RecordPage::tr("总宽合格率"));
                }
                else
                {
                    d->_table->setItem(i * 7 + 5, 1, new QTableWidgetItem(RecordPage::tr("总宽合格率")));
                }

                item = d->_table->item(i * 7 + 6, 1);
                if (item)
                {
                    item->setText(RecordPage::tr("检测总数"));
                }
                else
                {
                    d->_table->setItem(i * 7 + 6, 1, new QTableWidgetItem(RecordPage::tr("检测总数")));
                }
            }

            for(int i = 0; i < dn; i++)
            {
                for (int j = 0; j < formulars.size(); j++)
                {
                    QTableWidgetItem* item = d->_table->item(j * 7 + 0, i + 2);
                    if(item)
                    {
                        item->setText(QString::number(datas[i][formulars[j]].tcp, 'f', 2));
                    }
                    else
                    {
                        d->_table->setItem(j * 7 + 0, i + 2, new QTableWidgetItem(QString::number( datas[i][formulars[j]].tcp, 'f', 2)));
                    }

                    item = d->_table->item(j * 7 + 1, i + 2);
                    if(item)
                    {
                        item->setText(QString::number(datas[i][formulars[j]].tcpk, 'f', 2));
                    }
                    else
                    {
                        d->_table->setItem(j * 7 + 1, i + 2, new QTableWidgetItem(QString::number(datas[i][formulars[j]].tcpk, 'f', 2)));
                    }

                    item = d->_table->item(j * 7 + 2, i + 2);
                    if(item)
                    {
                        item->setText(QString::number((100.0 * datas[i][formulars[j]].tokRatio), 'f', 1) + "%");
                    }
                    else
                    {
                        d->_table->setItem(j * 7 + 2, i + 2, new QTableWidgetItem(QString::number((100.0 * datas[i][formulars[j]].tokRatio), 'f', 1)+ "%"));
                    }

                    item = d->_table->item(j * 7 + 3, i + 2);
                    if(item)
                    {
                        item->setText(QString::number(datas[i][formulars[j]].wcp, 'f', 2));
                    }
                    else
                    {
                        d->_table->setItem(j * 7 + 3, i + 2, new QTableWidgetItem(QString::number(datas[i][formulars[j]].wcp, 'f', 2)));
                    }

                    item = d->_table->item(j * 7 + 4, i + 2);
                    if(item)
                    {
                        item->setText(QString::number(datas[i][formulars[j]].wcpk, 'f', 2));
                    }
                    else
                    {
                        d->_table->setItem(j * 7 + 4, i + 2, new QTableWidgetItem(QString::number(datas[i][formulars[j]].wcpk, 'f', 2)));
                    }

                    item = d->_table->item(j * 7 + 5, i + 2);
                    if (item)
                    {
                        item->setText(QString::number((100.0 * datas[i][formulars[j]].wokRatio), 'f', 1) + "%");
                    }
                    else
                    {
                        d->_table->setItem(j * 7 + 5, i + 2, new QTableWidgetItem(QString::number((100.0 * datas[i][formulars[j]].wokRatio), 'f', 1) + "%"));
                    }

                    item = d->_table->item(j * 7 + 6, i + 2);
                    if (item)
                    {
                        item->setText(QString::number(datas[i][formulars[j]].count));
                    }
                    else
                    {
                        d->_table->setItem(j * 7 + 6, i + 2, new QTableWidgetItem(QString::number(datas[i][formulars[j]].count)));
                    }
                
                }
            }
#endif
        }

        void statisticsRatioDlg::onExport()
        {
            OI_F(statisticsRatioDlg);

            QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件")
                , PLScanner::instance()->excelDir + "/" +  d->_month->month().toString("yyyyMM") + "-" + d->_order->currentText() + ".xlsx"
                , tr("(*.xlsx)"));

            if(fileName.isEmpty())
            {
                OiAlerter() << tr("文件名为空，无法保存！");
                return;
            }

            PLScanner::instance()->excelDir = QFileInfo(fileName).absolutePath();

            QXlsx::Document xlsx;
            int row = 1;
            int col = 1;

            QXlsx::Format topFormat1;
            topFormat1.setFontBold(true);
            topFormat1.setFontSize(20);

            QXlsx::Format topFormat2;
            topFormat2.setFontSize(18);

            QXlsx::Format titleFormat;
            titleFormat.setFontBold(true);
            titleFormat.setVerticalAlignment(QXlsx::Format::AlignVCenter);
            titleFormat.setHorizontalAlignment(QXlsx::Format::AlignHCenter);

            xlsx.mergeCells(QXlsx::CellRange(1, 1, 1, 3), topFormat1);
            xlsx.mergeCells(QXlsx::CellRange(1, 4, 1, 6), topFormat2);
            xlsx.mergeCells(QXlsx::CellRange(1, 9, 1, 11), topFormat1);
            xlsx.mergeCells(QXlsx::CellRange(1, 12, 1, 14), topFormat2);

            xlsx.write(row, 1, tr("统计时间"));
            xlsx.write(row, 4, d->_month->month().toString("yyyyMM"));
            xlsx.write(row, 9, tr("班次"));
            xlsx.write(row, 12, d->_order->currentText());

            row = 2;
            col = 1;

            for(int i = 0; i < d->_table->columnCount(); i++)
            {
                xlsx.write(row, i + col, d->_table->horizontalHeaderItem(i)->text(), titleFormat);

                for (int j = 0; j < d->_table->rowCount(); j++)
                {
                    auto item = d->_table->item(j, i);
                    if (item)
                    {
                        xlsx.write(row + 1 + j, i + col, d->_table->item(j, i)->text());

                        int rowSpan =  d->_table->rowSpan(j, i);
                        if (rowSpan > 1)
                        {
                            xlsx.mergeCells(QXlsx::CellRange(row + 1 + j, i + col, row + 1 + j + rowSpan -1, i + col), titleFormat);
                        }
                    }
                }
            }

            if(xlsx.saveAs(fileName))
            {
                OiAlerter() << tr("保存成功");
            }
            else
            {
                OiAlerter() << tr("保存失败");
            }
        }

        class statisticsValueDlgImpl : public Impl<statisticsValueDlg>
        {
        public:
            QDateTimeEdit* _fromFilter;
            QDateTimeEdit* _endFilter;
            QComboBox* _order;
            QComboBox* _formular;
            QPushButton* _updateTable;
            QTableWidget* _table;
        };

        statisticsValueDlg::statisticsValueDlg(QWidget* parent /*= nullptr*/)
            : QDialog(parent, Qt::Dialog)
        {
            OI_I(statisticsValueDlg);
            QVBoxLayout* mainLayout = new QVBoxLayout(this);

            QHBoxLayout* tLayput = new QHBoxLayout();

            QLabel* fromLabel = new QLabel("开始时间");
            QLabel* endLabel = new QLabel("结束时间");
            QLabel* orderLabel = new QLabel("班次");
            QLabel* formularLabel = new QLabel("规格");

            d->_fromFilter = new QDateTimeEdit();
            d->_endFilter = new QDateTimeEdit();
            d->_order = new QComboBox();
            d->_formular = new QComboBox();

            d->_order->addItems({ statisticsValueDlg::tr("全部"), statisticsValueDlg::tr("A班"), statisticsValueDlg::tr("B班"), statisticsValueDlg::tr("C班") });
            d->_formular->addItems(Database::instance()->group("formula", Database::instance()->tableName()));

            d->_table = new QTableWidget();
            d->_table->verticalHeader()->hide();
            d->_table->horizontalHeader()->hide();
            d->_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

            d->_updateTable = new QPushButton("刷新");

            tLayput->addWidget(fromLabel);
            tLayput->addWidget(d->_fromFilter);
            tLayput->addStretch(1);
            tLayput->addWidget(endLabel);
            tLayput->addWidget(d->_endFilter);
            tLayput->addStretch(1);
            tLayput->addWidget(orderLabel);
            tLayput->addWidget(d->_order);
            tLayput->addStretch(1);
            tLayput->addWidget(formularLabel);
            tLayput->addWidget(d->_formular);
            tLayput->addStretch(8);
            tLayput->addWidget(d->_updateTable);

            mainLayout->addLayout(tLayput);
            mainLayout->addWidget(d->_table);

            connect(d->_updateTable, &QPushButton::clicked, this, &statisticsValueDlg::updateTable);
        }

        void statisticsValueDlg::setFilter(QDateTime from, QDateTime end, int classes, QString formular)
        {
            OI_F(statisticsValueDlg);

            d->_fromFilter->setDateTime(from);
            d->_endFilter->setDateTime(end);
            d->_order->setCurrentIndex(classes);
            d->_formular->setCurrentIndex(d->_order->findText(formular));

            updateTable();
        }

        void statisticsValueDlg::updateTable()
        {
            OI_F(statisticsValueDlg);

            QDateTime from = d->_fromFilter->dateTime();
            QDateTime end = d->_endFilter->dateTime();

            int team = d->_order->currentIndex() - 1;
            QString  formular = d->_formular->currentText();

            d->_table->clear();
            d->_table->setColumnCount(3);
            d->_table->setRowCount(18);
            
            d->_table->setSpan(0, 0, 6, 1);
            QTableWidgetItem* item = d->_table->item(0, 0);

            if(item)
            {
                item->setText(RecordPage::tr("合格率"));
            }
            else
            {
                d->_table->setItem(0, 0, new QTableWidgetItem(RecordPage::tr("合格率")));
            }

            d->_table->setSpan(6, 0, 6, 1);
            item = d->_table->item(6, 0);

            if(item)
            {
                item->setText(RecordPage::tr("CP"));
            }
            else
            {
                d->_table->setItem(6, 0, new QTableWidgetItem(RecordPage::tr("CP")));
            }

            d->_table->setSpan(12, 0, 6, 1);

            item = d->_table->item(12, 0);
            if(item)
            {
                item->setText(RecordPage::tr("CPK"));
            }
            else
            {
                d->_table->setItem(12, 0, new QTableWidgetItem(RecordPage::tr("CPK")));
            }

            for (int r = 0; r < 18; r += 6)
            {
                item = d->_table->item(r, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("宽度"));
                }
                else
                {
                    d->_table->setItem(r, 1, new QTableWidgetItem(RecordPage::tr("宽度")));
                }

                item = d->_table->item(r+1, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("边厚T1"));
                }
                else
                {
                    d->_table->setItem(r+1, 1, new QTableWidgetItem(RecordPage::tr("边厚T1")));
                }

                item = d->_table->item(r+2, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("中厚T2"));
                }
                else
                {
                    d->_table->setItem(r+2, 1, new QTableWidgetItem(RecordPage::tr("中厚T2")));
                }

                item = d->_table->item(r+3, 1);
                if(item)
                {
                    item->setText(RecordPage::tr("中厚T3"));
                }
                else
                {
                    d->_table->setItem(r+3, 1, new QTableWidgetItem(RecordPage::tr("中厚T3")));
                }

                item = d->_table->item(r + 4, 1);
                if (item)
                {
                    item->setText(RecordPage::tr("边厚T4"));
                }
                else
                {
                    d->_table->setItem(r + 4, 1, new QTableWidgetItem(RecordPage::tr("边厚T4")));
                }

        /*        item = d->_table->item(r + 5, 1);
                if (item)
                {
                    item->setText(RecordPage::tr("厚度5"));
                }
                else
                {
                    d->_table->setItem(r + 5, 1, new QTableWidgetItem(RecordPage::tr("厚度5")));
                }*/
            }

            if (formular.isEmpty())
            {
                OiAlerter() << "未选择规格，无法刷新统计表格";
                return;

            }

//             QList<int> resultValues;
//             QList<double> widthValues;
//             QList<double> spliceValues;
//             QList<double> dogearValues;
//             QList<double> openValues;
// 
//             Deps::ThicknessParams formularParams;
//             Deps::ThicknessProductParams::loadFromLocal(formularParams, formular);
//             double widthMax = formularParams.widthMax;
//             double widthMin = formularParams.widthMin;
//             double spliceMax = formularParams.thicknessMax;
//             double spliceMin = formularParams.thicknessMin;
//             double dogearMax = +formularParams.dogearError;
//             double dogearMin = -formularParams.dogearError;
//             double openMax = +formularParams.openError;
//             double openMin = 0.0;
// 
//             QSqlQuery query;
// 
//             QStringList queryString;
//             QString filterString;
// 
//             queryString.append(Database::instance()->spliceKeys);
//             queryString.append(Database::instance()->widthKeys);
//             queryString.append(Database::instance()->dogearKeys);
//             queryString.append(Database::instance()->openKeys);
// 
//             filterString.append(QString("AND formula = '%1'").arg(formular));
// 
//             if(team >= 0)
//             {
//                 filterString.append(QString("AND classes = %1 ").arg(team));
//             }
// 
//             
//             query.prepare(QString("SELECT insResult,%1 FROM %2 WHERE datetime BETWEEN '%3' AND '%4' %5")
//                 .arg(queryString.join(','))
//                 .arg(Database::instance()->tableName())
//                 .arg(from.toString("yyyy-MM-dd hh:mm:ss"))
//                 .arg(end.toString("yyyy-MM-dd hh:mm:ss"))
//                 .arg(filterString));
// 
//             query.exec();
// 
//             while(query.next())
//             {
//                 auto ir = query.value(0).toInt();
//                 auto ls = query.value(1).toDouble();
//                 auto cs = query.value(2).toDouble();
//                 auto rs = query.value(3).toDouble();
//                 auto w = query.value(4).toDouble();
//                 auto ld = query.value(5).toDouble();
//                 auto rd = query.value(6).toDouble();
//                 auto ov = query.value(7).toDouble();
// 
//                 resultValues << ir;
//                 widthValues << w;
//                 spliceValues << ls << cs << rs;
//                 dogearValues << ld << rd;
//                 openValues << ov;
//             }


            double widthRatio = 0.0;
            double thickness1Ratio = 0.0;
            double thickness2Ratio = 0.0;
            double thickness3Ratio = 0.0;
            double thickness4Ratio = 0.0;
            double thickness5Ratio = 0.0;

            double widthCP = 0.0;
            double thickness1CP = 0.0;
            double thickness2CP = 0.0;
            double thickness3CP = 0.0;
            double thickness4CP = 0.0;
            double thickness5CP = 0.0;
           
            double widthCPK = 0.0;
            double thickness1CPK = 0.0;
            double thickness2CPK = 0.0;
            double thickness3CPK = 0.0;
            double thickness4CPK = 0.0;
            double thickness5CPK = 0.0;

//             RecordPage::calCPCPK(widthValues, widthCP, widthCPK, widthMax, widthMin);
//             RecordPage::calCPCPK(spliceValues, spliceCP, spliceCPK, spliceMax, spliceMin);
//             RecordPage::calCPCPK(dogearValues, dogearCP, dogearCPK, dogearMax, dogearMin);
//             RecordPage::calCPCPK(openValues, openCP, openCPK, openMax, openMin);
//             RecordPage::calFPY(resultValues, spliceRatio, widthRatio, dogearRatio, openRatio);


            item = d->_table->item(0, 2);
            if(item)
            {
                item->setText(QString::number((100.0 * widthRatio), 'f', 1) + "%");
            }
            else
            {
                d->_table->setItem(0, 2, new QTableWidgetItem(QString::number((100.0 * widthRatio), 'f', 1) + "%"));
            }

            item = d->_table->item(1, 2);
            if(item)
            {
                item->setText(QString::number((100.0 * thickness1Ratio), 'f', 1) + "%");
            }
            else
            {
                d->_table->setItem(1, 2, new QTableWidgetItem(QString::number((100.0 * thickness1Ratio), 'f', 1) + "%"));
            }

            item = d->_table->item(2, 2);
            if(item)
            {
                item->setText(QString::number((100.0 * thickness2Ratio), 'f', 1) + "%");
            }
            else
            {
                d->_table->setItem(2, 2, new QTableWidgetItem(QString::number((100.0 * thickness2Ratio), 'f', 1) + "%"));
            }

            item = d->_table->item(3, 2);
            if(item)
            {
                item->setText(QString::number((100.0 * thickness3Ratio), 'f', 1) + "%");
            }
            else
            {
                d->_table->setItem(3, 2, new QTableWidgetItem(QString::number((100.0 * thickness3Ratio), 'f', 1) + "%"));
            }

            item = d->_table->item(4, 2);
            if (item)
            {
                item->setText(QString::number((100.0 * thickness4Ratio), 'f', 1) + "%");
            }
            else
            {
                d->_table->setItem(4, 2, new QTableWidgetItem(QString::number((100.0 * thickness4Ratio), 'f', 1) + "%"));
            }

            item = d->_table->item(5, 2);
            if (item)
            {
                item->setText(QString::number((100.0 * thickness5Ratio), 'f', 1) + "%");
            }
            else
            {
                d->_table->setItem(5, 2, new QTableWidgetItem(QString::number((100.0 * thickness5Ratio), 'f', 1) + "%"));
            }

            item = d->_table->item(6, 2);
            if(item)
            {
                item->setText(QString::number(widthCP , 'f', 1));
            }
            else
            {
                d->_table->setItem(6, 2, new QTableWidgetItem(QString::number(widthCP, 'f', 1)));
            }

            item = d->_table->item(7, 2);
            if (item)
            {
                item->setText(QString::number(thickness1CP, 'f', 1));
            }
            else
            {
                d->_table->setItem(7, 2, new QTableWidgetItem(QString::number(thickness1CP, 'f', 1)));
            }
            item = d->_table->item(8, 2);
            if (item)
            {
                item->setText(QString::number(thickness2CP, 'f', 1));
            }
            else
            {
                d->_table->setItem(8, 2, new QTableWidgetItem(QString::number(thickness2CP, 'f', 1)));
            }
            item = d->_table->item(9, 2);
            if (item)
            {
                item->setText(QString::number(thickness3CP, 'f', 1));
            }
            else
            {
                d->_table->setItem(9, 2, new QTableWidgetItem(QString::number(thickness3CP, 'f', 1)));
            }
            item = d->_table->item(10, 2);
            if (item)
            {
                item->setText(QString::number(thickness4CP, 'f', 1));
            }
            else
            {
                d->_table->setItem(10, 2, new QTableWidgetItem(QString::number(thickness4CP, 'f', 1)));
            }
            item = d->_table->item(11, 2);
            if (item)
            {
                item->setText(QString::number(thickness5CP, 'f', 1));
            }
            else
            {
                d->_table->setItem(11, 2, new QTableWidgetItem(QString::number(thickness5CP, 'f', 1)));
            }
            item = d->_table->item(12, 2);
            if (item)
            {
                item->setText(QString::number(widthCPK, 'f', 1));
            }
            else
            {
                d->_table->setItem(12, 2, new QTableWidgetItem(QString::number(widthCPK, 'f', 1)));
            }
            item = d->_table->item(13, 2);
            if (item)
            {
                item->setText(QString::number(thickness1CPK, 'f', 1));
            }
            else
            {
                d->_table->setItem(13, 2, new QTableWidgetItem(QString::number(thickness1CPK, 'f', 1)));
            }
            item = d->_table->item(14, 2);
            if (item)
            {
                item->setText(QString::number(thickness2CPK, 'f', 1));
            }
            else
            {
                d->_table->setItem(14, 2, new QTableWidgetItem(QString::number(thickness2CPK, 'f', 1)));
            }
            item = d->_table->item(15, 2);
            if (item)
            {
                item->setText(QString::number(thickness3CPK, 'f', 1));
            }
            else
            {
                d->_table->setItem(15, 2, new QTableWidgetItem(QString::number(thickness3CPK, 'f', 1)));
            }

            item = d->_table->item(16, 2);
            if (item)
            {
                item->setText(QString::number(thickness4CPK, 'f', 1));
            }
            else
            {
                d->_table->setItem(16, 2, new QTableWidgetItem(QString::number(thickness4CPK, 'f', 1)));
            }

            item = d->_table->item(17, 2);
            if (item)
            {
                item->setText(QString::number(thickness5CPK, 'f', 1));
            }
            else
            {
                d->_table->setItem(17, 2, new QTableWidgetItem(QString::number(thickness5CPK, 'f', 1)));
            }
      
        }

        class xrGraphicDlgImpl : public Impl<xrGraphicDlg>
        {
        public:
            QDateTimeEdit* _fromFilter;
            QDateTimeEdit* _endFilter;
            QComboBox* _name;
            QComboBox* _formular;

            ValueInDateChartView *_chartViewX;
            ValueInDateChartView *_chartViewR;
            ValueInDateChart* _chartX;
            ValueInDateChart* _chartR;
            QTableWidget* _table;
            QPushButton *_update;
        public:
            void setDataGroup(QList<double> lstValue, int row, int col, QList<QList<double>>& lstDatas );//将数据分组
        };

        void xrGraphicDlgImpl::setDataGroup(QList<double> lstValue, int row, int col, QList<QList<double>>& lstDatas)//将数据分组
        {
            int beginIndex = lstValue.size() % (row * col)-1  ;
            beginIndex = beginIndex > 0 ? beginIndex : 0;
            int cols = lstValue.size() / row;
            int inter = cols / col;
            for (int i = 0; i < row; i++)
            {
                QList<double> tempData;
                
                double ave = 0.0;
                double sum = 0.0;
                for (int j = 0; j < cols; j++)
                {
                    if ((j % inter > 0 && j != 0) || (j == 0) )
                    {
                        if (beginIndex < lstValue.size())
                        {
                            sum += lstValue[beginIndex];
                        }

                        beginIndex++;
                    }
                    else
                    {
                        ave = sum / inter;
                        tempData.append(ave);
                        sum = 0.0;
                    }
                }
                lstDatas.append(tempData);
            }
        }

        xrGraphicDlg::xrGraphicDlg(QWidget* parent /*= nullptr*/)
        {
            OI_I(xrGraphicDlg);
            QVBoxLayout* mainLayout = new QVBoxLayout(this);

            QHBoxLayout* tLayput = new QHBoxLayout();

            d->_fromFilter = new QDateTimeEdit();

            d->_endFilter = new QDateTimeEdit();

            d->_fromFilter->setDateTime(QDateTime::currentDateTime().addDays(-1));

            d->_endFilter->setDateTime(QDateTime::currentDateTime());

            d->_update = new QPushButton(xrGraphicFixedDlg::tr("刷新"));

            QLabel * nameLabel = new QLabel(xrGraphicDlg::tr("测量点"));

            QLabel * formularLabel = new QLabel(xrGraphicDlg::tr("规格"));

            d->_name = new QComboBox();

            d->_name->addItems({ "边厚T1", "中厚T2", "中厚t3", "边厚T4", "总宽"});

            d->_formular = new QComboBox();
            d->_formular->addItems(Database::instance()->group("formula", Database::instance()->tableName()));
            d->_chartX = new ValueInDateChart();

            d->_chartR = new ValueInDateChart();

            d->_chartX->setYFormat("%.2f");

            d->_chartR->setYFormat("%.2f");

            d->_chartViewX = new ValueInDateChartView(d->_chartX);

            d->_chartViewR = new ValueInDateChartView(d->_chartR);

            d->_table = new QTableWidget();
            d->_table->setRowCount(3);
            d->_table->setFixedHeight(150);
            QStringList sideList;
            sideList << "" << xrGraphicFixedDlg::tr("X") << xrGraphicFixedDlg::tr("R");
            d->_table->setVerticalHeaderLabels(sideList);
            d->_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

            tLayput->addWidget(d->_update);
            tLayput->addWidget(d->_fromFilter);
            tLayput->addWidget(d->_endFilter);
            tLayput->addStretch();
            tLayput->addWidget(formularLabel);
            tLayput->addWidget(d->_formular);
            tLayput->addWidget(nameLabel);
            tLayput->addWidget(d->_name);

            mainLayout->addLayout(tLayput, 0);
            mainLayout->addWidget(d->_chartViewX, 1);
            mainLayout->addWidget(d->_chartViewR, 1);

            mainLayout->addWidget(d->_table, 0);

            connect(d->_update, &QPushButton::clicked, this, &xrGraphicDlg::update);
            connect(d->_formular, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &xrGraphicDlg::update);
            connect(d->_name, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &xrGraphicDlg::update);
            update();
        }

        void xrGraphicDlg::update()
        {
            
            OI_F(xrGraphicDlg);
            QString strFormula = d->_formular->currentText();
            QString strThickness = d->_name->currentText();

            QSqlQuery query;
            QList<double> lstValue;
            QDateTime from = d->_fromFilter->dateTime();
            QDateTime end = d->_endFilter->dateTime();
            QString str = QString("SELECT %1 "
                "FROM %2 WHERE datetime BETWEEN '%3' AND '%4' and formula = '%5'")
                .arg(strThickness)
                .arg(Database::instance()->tableName())
                .arg(from.toString("yyyy-MM-dd hh:mm:ss"))
                .arg(end.toString("yyyy-MM-dd hh:mm:ss"))
                .arg(strFormula);

            query.prepare(QString("SELECT %1 "
                "FROM %2 WHERE datetime BETWEEN '%3' AND '%4' and formula='%5'")
                .arg(strThickness)
                .arg(Database::instance()->tableName())
                .arg(from.toString("yyyy-MM-dd hh:mm:ss"))
                .arg(end.toString("yyyy-MM-dd hh:mm:ss"))
                .arg(strFormula));

            query.exec();
            while (query.next())
            {
                double thickness = query.value(0).toDouble();
                lstValue.append(thickness);
            }
            if (lstValue.size()<125)
            {
                return;
            }
            QList<double> xs;
            QList<double> rs;
            /*QList<double> xs = { 1.0, 1.1, 1.2, 0.9, 0.8, 0.7, 1.2, 1.3, 1.0, 0.9, 1.0, 1.1, 1.0, 0.9, 0.8, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.1, 0.9, 0.9, 0.8 };
            QList<double> rs = { 0.01, 0.02, 0.03, 0.02, 0.03, 0.02, 0.04, 0.01, 0.02, 0.04, 0.03, 0.01, 0.02, 0.04, 0.04, 0.01, 0.02, 0.03, 0.04, 0.01, 0.02, 0.03, 0.04, 0.04, 0.03 };*/
     
            int row = 25;
            int col = lstValue.size() / row;
            QList<QList<double>> lstDatas;
            d->_table->clearContents();
            d->_table->setColumnCount(row);
            d->setDataGroup(lstValue, row, 5, lstDatas);
            double xValue = 0.0;
            double rValue = 0.0;
           for (int i = 0; i < row; i++)
           {
               double maxValue = lstDatas[i][0];
               double minValue = lstDatas[i][0];
               double ave = 0.0;
               for (int j = 0; j < lstDatas[i].size();j++)
               {
                   if (lstDatas[i][j] > maxValue)
                   {
                       maxValue = lstDatas[i][j];
                   }
                   if (lstDatas[i][j] < minValue)
                   {
                       minValue = lstDatas[i][j];
                   }
                   ave += lstDatas[i][j];
               }
               xValue += ave / lstDatas[i].size();
               rValue += maxValue - minValue;
               xs.append(ave / lstDatas[i].size());
               rs.append(maxValue - minValue);
           }
           double dx = xValue / lstDatas.size();
           double dr = rValue / lstDatas.size();
            for (int i = 0; i < d->_table->columnCount(); i++)
            {
                QTableWidgetItem* item = d->_table->item(0, i);
                if (item)
                {
                    item->setText(QString::number(i));
                }
                else
                {
                    d->_table->setItem(0, i, new QTableWidgetItem(QString::number(i)));
                }

                item = d->_table->item(1, i);
                if (item)
                {
                    item->setText(QString::number(xs[i]));
                }
                else
                {
                    d->_table->setItem(1, i, new QTableWidgetItem(QString::number(xs[i])));
                }

                item = d->_table->item(2, i);

                if (item)
                {
                    item->setText(QString::number(rs[i]));
                }
                else
                {
                    d->_table->setItem(2, i, new QTableWidgetItem(QString::number(rs[i])));
                }
            }

            d->_chartX->setValues(0, xs, 25);
            d->_chartR->setValues(0, rs, 25);

            double uclx = dx + 0.577 * dr;
            double lclx = dx - 0.577 * dr;
            QMetaObject::invokeMethod(d->_chartViewX, "setLimit", Qt::QueuedConnection, Q_ARG(double, uclx), Q_ARG(double,lclx));
            QMetaObject::invokeMethod(d->_chartViewR, "setLimit", Qt::QueuedConnection, Q_ARG(double, 2.114 * dr), Q_ARG(double, 0));
        }

        class RecordPageImpl : public Impl<RecordPage>, public QSqlQueryModel
        {
        public:
            void init();
            void updateData();
            QString queryString(const QDateTime& from, const QDateTime& end);
            void removeDatabaseItem(const QString dt);

        public:
             QVariant data(const QModelIndex &index, int role) const;

             QVariant headerData(int section, Qt::Orientation orientation,
                 int role = Qt::DisplayRole) const;

        public:
            QPushButton* _fresh;
            QPushButton* _export;
            QPushButton* _statisticsTime;
            QPushButton* _statisticsRatio;
            QPushButton* _statisticsData;
            QPushButton* _xrGraphics;

            QDateTimeEdit* _fromFilter;
            QDateTimeEdit* _endFilter;

            //QLabel* _modeFilterLabel;
            QLabel* _formulaFilterLabel;
            QLabel* _userFilterLabel;
            QLabel* _resultFilterLabel;
            QLabel* _orderFilterLabel;

            //QComboBox* _modeFilter;
            QComboBox* _formulaFilter;
            QComboBox* _userFilter;
            QComboBox* _resultFilter;
            QComboBox* _orderFilter;

            QComboBox* _category;
            QTableView* _tableView;
            QStringList _headList;
            QStringList _queryList;
            QSortFilterProxyModel* _sqlproxy;
        };

        void RecordPageImpl::init()
        {
            OI_Q(RecordPage);

            QVBoxLayout* mainLayout = new QVBoxLayout(q);

            QHBoxLayout* tLayout = new QHBoxLayout();

            _fresh = new QPushButton(RecordPage::tr("刷新"),q);

            _export = new QPushButton(RecordPage::tr("导出"),q);

            _statisticsTime = new QPushButton(RecordPage::tr("稼动时间"),q);
            _statisticsRatio = new QPushButton(RecordPage::tr("统计报表"),q);
            _statisticsData = new QPushButton(RecordPage::tr("数据统计"),q);
            _xrGraphics = new QPushButton(RecordPage::tr("X_R图"), q);

            //_modeFilterLabel = new QLabel("模式");
            _formulaFilterLabel = new QLabel("规格");
            _resultFilterLabel = new QLabel("结果");
            _userFilterLabel = new QLabel("用户");
            _orderFilterLabel = new QLabel("班次");

            //_modeFilter = new QComboBox();
            _formulaFilter = new QComboBox();
            _resultFilter = new QComboBox();
            _userFilter = new QComboBox();
            _orderFilter = new QComboBox();

            //_modeFilter->addItems({ "正常", "点检" });
            _resultFilter->addItems({ "全部", "合格", "预警" ,"报警" });
            _orderFilter->addItems({ "全部", "A班", "B班", "C班" });

            _fromFilter = new QDateTimeEdit(q);
            _fromFilter->setCalendarPopup(true);
            _endFilter = new QDateTimeEdit(q);
            _endFilter->setCalendarPopup(true);

            _category = new QComboBox(q);
            _category->addItems({ RecordPage::tr("近24小时"), RecordPage::tr("近1周"), RecordPage::tr("近1月"), RecordPage::tr("近1年") });

            tLayout->addWidget(_fresh);
            tLayout->addWidget(_export);
            //tLayout->addWidget(_modeFilterLabel);
            //tLayout->addWidget(_modeFilter);
            tLayout->addWidget(_formulaFilterLabel);
            tLayout->addWidget(_formulaFilter);
            tLayout->addWidget(_resultFilterLabel);
            tLayout->addWidget(_resultFilter);
            tLayout->addWidget(_userFilterLabel);
            tLayout->addWidget(_userFilter);
            tLayout->addWidget(_orderFilterLabel);
            tLayout->addWidget(_orderFilter);
            tLayout->addStretch(1);
            tLayout->addWidget(_fromFilter);
            tLayout->addWidget(_endFilter);
            tLayout->addWidget(_category);
            tLayout->addWidget(_statisticsTime);
            tLayout->addWidget(_statisticsRatio);
            tLayout->addWidget(_statisticsData);
            tLayout->addWidget(_xrGraphics);

            _statisticsTime->hide();
            _statisticsRatio->hide();
            _statisticsData->hide();
            _xrGraphics->hide();

            _sqlproxy = new QSortFilterProxyModel(this);
            _sqlproxy->setSourceModel(this);

            _tableView = new QTableView(q);
            _tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);  
            _tableView->setModel(_sqlproxy);
            _tableView->setAlternatingRowColors(true);
            _tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

            _tableView->setSortingEnabled(true);
            _tableView->setContextMenuPolicy(Qt::CustomContextMenu);

            _queryList << "fullHeight" << "waistHeight" << "endPointWidth" << "waistWidth" << "bottomWidth" << "area";

            _headList << RecordPage::tr("日期") << RecordPage::tr("配方名称") << RecordPage::tr("用户") << RecordPage::tr("结果") << "总高" << "腰高" << "端点宽" << "腰宽" << "底部宽" << "截面积";

            mainLayout->addLayout(tLayout);
            mainLayout->addWidget(_tableView);

            q->connect(_fresh, SIGNAL(clicked()), q, SLOT(update()));
            q->connect(_export, SIGNAL(clicked()), q, SLOT(exportExcel()));
            q->connect(_statisticsTime, SIGNAL(clicked()), q, SLOT(statisticsTime()));
            q->connect(_statisticsRatio, SIGNAL(clicked()), q, SLOT(statisticsRatio()));
            q->connect(_statisticsData, SIGNAL(clicked()), q, SLOT(statisticsData()));
            q->connect(_xrGraphics, SIGNAL(clicked()), q, SLOT(xrGraphics()));

            q->connect(_category, SIGNAL(currentIndexChanged(int)), q, SLOT(onCategoryChanged(int)));
            q->connect(_tableView, SIGNAL(doubleClicked(const QModelIndex &)), q, SLOT(onTableDoubleClicked(const QModelIndex &)));
            q->connect(_tableView, SIGNAL(customContextMenuRequested(const QPoint&)), q, SLOT(deleteItem(const QPoint &)));
        }

        void RecordPageImpl::updateData()
        {
            QDateTime dt_from = _fromFilter->dateTime();
            int dt_from_i = dt_from.toTime_t();

            QDateTime dt_end = _endFilter->dateTime();
            int dt_end_i = dt_end.toTime_t();


            if(Database::instance()->open())
            {
                beginResetModel();

                QString mqueryString = queryString(dt_from, dt_end);

                setQuery(mqueryString);

                while (canFetchMore())
                {
                    fetchMore();
                }

                endResetModel();
            }
        }

        QString RecordPageImpl::queryString(const QDateTime& from, const QDateTime& end)
        {
            QString filterString;

            if (_formulaFilter->currentIndex() > 0)
            {
                filterString.append(QString("AND formula = '%1'").arg(_formulaFilter->currentText()));
            }

            if(_resultFilter->currentIndex() == 1)
            {
                filterString.append(QString("AND result = %1 ").arg(WorkResult::RC_Success));
            }
            else if(_resultFilter->currentIndex() == 2)
            {
                filterString.append(QString("AND result = %1 ").arg(WorkResult::RC_Warning));
            }
            else if (_resultFilter->currentIndex() == 3)
            {
                filterString.append(QString("AND result = %1 ").arg(WorkResult::RC_Error));
            }

            if (_userFilter->currentIndex() > 0)
            {
                filterString.append(QString("AND user = '%1'").arg(_userFilter->currentText()));
            }

            if (_orderFilter->currentIndex() > 0)
            {
                filterString.append(QString("AND team = %1 ").arg(_orderFilter->currentIndex() - 1));
            }
     
            return QString("SELECT %1 FROM %2 WHERE datetime BETWEEN '%3' AND '%4' %5")
                .arg("datetime,formula,user,result," + _queryList.join(','))
                .arg(Database::instance()->tableName())
                .arg(from.toString("yyyy-MM-dd hh:mm:ss"))
                .arg(end.toString("yyyy-MM-dd hh:mm:ss"))
                .arg(filterString);
        }

        void RecordPageImpl::removeDatabaseItem(const QString dt)
        {
            QSqlQuery query;

            query.prepare(QString("DELETE FROM %1 WHERE datetime = '%2'")
                .arg(Database::instance()->tableName())
                .arg(dt));

            query.exec();
        }

        QVariant RecordPageImpl::data(const QModelIndex &index, int role) const
        {
            if(role == Qt::BackgroundColorRole)
            {
                if(index.column() == 3)
                {
                    auto value = QSqlQueryModel::data(index, Qt::DisplayRole).toInt();
                    if (value == WorkResult::RC_Success)
                    {
                        return QColor(Qt::darkGreen);
                    }
                    else if (value == WorkResult::RC_Warning)
                    {
                        return QColor(Qt::darkYellow);
                    }
                    else 
                    {
                        return QColor(Qt::darkRed);
                    }
                }
            }
            
            if (role == Qt::DisplayRole)
            {
                if(index.column() == 3)
                {
                    auto value = QSqlQueryModel::data(index, Qt::DisplayRole).toInt();

                    return InspectionString(value);
                }
            }

            return QSqlQueryModel::data(index, role);
        }

        QVariant RecordPageImpl::headerData(int section, Qt::Orientation orientation, int role) const
        {
            if(role == Qt::DisplayRole)
            {
                if(orientation == Qt::Horizontal)
                {
                    return  _headList[section];
                }
            }

            return QSqlQueryModel::headerData(section, orientation, role);
        }

        RecordPage::RecordPage(QWidget * parent /*= nullptr*/)
            :PageAbstract(parent)
        {
            OI_I(RecordPage)->init();
        }

        void RecordPage::onCategoryChanged(int index)
        {
            OI_F(RecordPage);

            QDateTime dt_end = QDateTime::currentDateTime();
            QDateTime dt_from;

            switch(index)
            {
            case 0:
                dt_from = QDateTime::fromString(dt_end.toString("yyyyMMdd hh"), "yyyyMMdd hh").addSecs(-23 * 3600);
            break;
            case 1:
                dt_from = QDateTime::fromString(dt_end.toString("yyyyMMdd"), "yyyyMMdd").addDays(-6);
            break;
            case 2:
                dt_from = QDateTime::fromString(dt_end.toString("yyyyMMdd"), "yyyyMMdd").addDays(-29);
            break;
            case 3:
                dt_from = QDateTime::fromString(dt_end.toString("yyyyMM"), "yyyyMM").addMonths(-11);
            break;
            }

            d->_fromFilter->setDateTime(dt_from);
            d->_endFilter->setDateTime(dt_end);

            update();
        }

        void RecordPage::setCategoryIndex(int index)
        {
            OI_F(RecordPage);

            d->_category->blockSignals(true);
            d->_category->setCurrentIndex(index);
            d->_category->blockSignals(false);

            onCategoryChanged(index);
        }

        void RecordPage::updateFormuala()
        {
            OI_F(RecordPage);

            d->_formulaFilter->clear();

            d->_formulaFilter->addItem(RecordPage::tr("全部"));
            d->_formulaFilter->addItems(Database::instance()->group("formula", Database::instance()->tableName()));

            d->_formulaFilter->setCurrentIndex(0);
        }

        void RecordPage::updateUser()
        {
            OI_F(RecordPage);

            d->_userFilter->clear();

            d->_userFilter->addItem(RecordPage::tr("全部"));
            d->_userFilter->addItems(Database::instance()->group("user", Database::instance()->tableName()));

            d->_userFilter->setCurrentIndex(0);
        }

        void RecordPage::updateResult()
        {
            OI_F(RecordPage);
            d->_resultFilter->setCurrentIndex(0);
        }

        void RecordPage::updateOrder()
        {
            OI_F(RecordPage);
            d->_orderFilter->setCurrentIndex(0);
        }

        void RecordPage::updatePermission()
        {
            OI_F(RecordPage);
            d->_statisticsTime->setEnabled( UserManage::instance()->permission() & PT_ViewTimeStatistics);
            d->_statisticsRatio->setEnabled( UserManage::instance()->permission() & PT_ViewFPYStatistics);
            d->_statisticsData->setEnabled(UserManage::instance()->permission() & PT_ViewStatistics);
            d->_xrGraphics->setEnabled(UserManage::instance()->permission() & PT_ViewXRGraphics);
        }

        void RecordPage::onTableDoubleClicked(const QModelIndex & index)
        {
//            OI_F(RecordPage);
//            
//            auto r = index.row();
//            auto c = index.column();
//
//            if (r < 0  || c != 3)
//            {
//                return;
//            }
//
//            if (!(UserManage::instance()->permission() & PT_ViewData))
//            {
//                OiAlerter() << RecordPage::tr("查看数据权限不足");
//                return;
//            }
//
//            auto model = d->_tableView->model();
//            auto dt = model->data(model->index(r, 0)).toString();
//            
//            QSqlQuery query;
//
//             QString queryString = QString("SELECT id FROM %1 WHERE datetime = '%2'")
//                 .arg(Database::instance()->tableName())
//                 .arg(dt);
// 
//             query.prepare(queryString);
// 
//             query.exec();
// 
//             if (query.next())
//             {
//                 auto id = query.value(0).toInt();
//                 auto spliceArray = Database::instance()->querySpliceData(id);
//                 QList<QPointF> splices;
// 
//                 if(!spliceArray.isEmpty())
//                 {
//                     QDataStream sCurves(&spliceArray, QIODevice::ReadOnly);
//                     sCurves >> splices;
//                 }
// 
//                 if(!splices.isEmpty())
//                 {
//                     SpliceDataDlg dlg(this);
//                     dlg.resize(800, 300);
//                     dlg.setData(splices);
//                     dlg.exec();
//                 }
//             }
        }

        void RecordPage::update()
        {
            OI_F(RecordPage);
            d->updateData();
        }

        void RecordPage::exportExcel()
        {
            OI_F(RecordPage);

            QList<int> srs;

            auto model = d->_tableView->model();

            QModelIndexList selectedAngleRows = d->_tableView->selectionModel()->selectedRows();

            foreach(const QModelIndex & index, selectedAngleRows)
            {
                srs.append(index.row());
            }

            if(selectedAngleRows.size() == 0)
            {
                auto ret = QMessageBox::information(this, tr("确认"), tr("是否保存全部的%1行数据").arg(model->rowCount()),
                    QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);

                if(ret == QMessageBox::Yes)
                {
                    for(int i = 0; i < model->rowCount(); i++)
                    {
                        srs << i;
                    }
                }
                else
                {
                    return;
                }
            }

            QString fileName = QFileDialog::getSaveFileName(this, tr("保存文件")
                , PLScanner::instance()->excelDir + "/" + tr("未命名.xlsx")
                , tr("(*.xlsx)"));

            if(fileName.isEmpty())
            {
                OiAlerter() << tr("文件名为空，无法保存！");
                return;
            }

            PLScanner::instance()->excelDir = QFileInfo(fileName).absolutePath();

            QXlsx::Document xlsx;

            int col = 1;
            for (auto head : d->_headList)
            {
                xlsx.write(1, col++, head);
            }
            
            int row = 2;
            for (auto r : srs)
            {
                for (int i = 0; i < d->_headList.size(); i++)
                {
                    xlsx.write(row, i+1, model->data(model->index(r, i)));
                }

                row++;
            }
            if (xlsx.saveAs(fileName))
            {
                OiAlerter() << tr("保存成功");
            }
            else
            {
                OiAlerter() << tr("保存失败");
            }
        }

        void RecordPage::statisticsTime()
        {
            OI_F(RecordPage);

            statisticsTimeDlg dlg(this);
            dlg.setWindowTitle(tr("稼动时间统计"));
            dlg.resize(1600, 700);
            dlg.exec();
        }

        void RecordPage::statisticsRatio()
        {
            OI_F(RecordPage);

            statisticsRatioDlg dlg(this);
            dlg.setWindowTitle(tr("报表统计"));
            auto dg = QApplication::desktop()->availableGeometry();
            dlg.resize(dg.width() - 100, 900);
            dlg.exec();
        }

        void RecordPage::statisticsData()
        {
            OI_F(RecordPage);

            statisticsValueDlg dlg(this);
            dlg.setWindowTitle(tr("数据统计"));
            dlg.setFilter(d->_fromFilter->dateTime(), d->_endFilter->dateTime(), d->_orderFilter->currentIndex(), d->_formulaFilter->currentText());
            dlg.resize(800, 600);
            dlg.exec();
        }

        void RecordPage::showEvent(QShowEvent *event)
        {
            OI_F(RecordPage);

            updateFormuala();
            updateUser();
            updateResult();
            updateOrder();
            updatePermission();
            setCategoryIndex(0);
        }

        void RecordPage::deleteItem(const QPoint& pos)
        {
            OI_F(RecordPage);

            auto index = d->_tableView->indexAt(pos);

            auto r = index.row();

            if(r < 0)
            {
                return;
            }

            QList<int> srs;

            srs.append(r);

            auto model = d->_tableView->model();

            QModelIndexList selectedAngleRows = d->_tableView->selectionModel()->selectedIndexes();

            foreach(const QModelIndex & index, selectedAngleRows)
            {
                auto sr = index.row();
                if (!srs.contains(sr))
                {
                    srs.append(sr);
                }
            }

            QMenu menu;
            auto removeAction = menu.addAction(tr("删除"));

            removeAction->setEnabled(PLScanner::instance()->super || ( UserManage::instance()->permission() & PT_DeleteData ));

            auto ret = menu.exec(d->_tableView->mapToGlobal(pos));

            if(removeAction == ret)
            {
               
                auto ret = QMessageBox::information(this, tr("确认"), tr("是否删除选中的%1行数据").arg(srs.count()),
                    QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);

                if(ret == QMessageBox::Yes)
                {
                    for (auto ir : srs)
                    {
                        auto dt = model->data(model->index(ir, 0)).toString();
                        d->removeDatabaseItem(dt);
                    }
                    
                    d->updateData();
                }
                else
                {
                    return;
                }
            }
        }

        void RecordPage::xrGraphics()
        {
            OI_F(RecordPage);

            xrGraphicDlg dlg(this);
            dlg.setWindowTitle(tr("X-R 图"));
            auto dg = QApplication::desktop()->availableGeometry();
            dlg.resize(dg.width() - 100, dg.height() - 100);
            dlg.exec();
        }

    }

}